namespace cpputils
{

struct command_line_option_error : public runtime_error
{
	command_line_option_error(const string& Msg);
};

struct command_line_option
{
	vector<string> names;
	string argument;
	string default_value;
	string info;
};

struct command_line_argument
{
	string option;
	string argument;

	command_line_argument(const string& SetOption = "", const string& SetArg = "");
};

class command_line_options
{
public:
	void clear();
	bool empty() const;
	int size() const;
	const command_line_option& operator[](int I) const;
	command_line_options& add(const string& Name);
	command_line_options& add_name(const string& Name);
	command_line_options& set_argument(const string& Argument, const string& Value = "");
	command_line_options& set_info(const string& Info);

	void show_help() const;
	void show_help(const command_line_option& Option) const;

	vector<command_line_argument> parse(int Argc, char* Argv[]) const;
	vector<command_line_argument> parse(subarray<const string> Args) const;

private:
	vector<command_line_option> Options;
	int Current;
};

class command_line_options_handler
{
public:
	command_line_options_handler();
	command_line_options_handler& add_usage(const string& S);
	command_line_options& options();
	void set_front_info(const string& S);
	void set_back_info(const string& S);
	void set_arguments(int SetArgc, char* SetArgv[]);
	const string& get_program_name() const;
	void show_usages() const;
	void show_help() const;
	vector<command_line_argument> parse() const;

private:
	vector<string> Usages;
	command_line_options Options;
	string FrontInfo, BackInfo;
	int Argc;
	char** Argv;
	string ProgName;

	string extract_program_name(const string& Path) const;
};

namespace command_line_options_impl
{
	const int ConsoleWidth = 80;
	void indented_print(int Indent, const string& S, int Cursor = 0);
}

}
